﻿using Microsoft.Win32;
using System.Diagnostics;
using System.Runtime.Versioning;

namespace Sage.WindowsProcess.AutoStartup
{


    /// <summary>
    /// 提供Windows系统下程序开机自启动管理功能
    /// </summary>
    /// <param name="appName">应用程序名称</param>
    /// <param name="appPath">可选的设置其它程序开机启动，为空时则设置自身(主程序)开机启动。</param>
    /// <param name="arguments">可选的命令行参数</param>
    [SupportedOSPlatform("windows")]
    public class StartupService(string appName, string? appPath = null, string? arguments = null) : IStartupService
    {
        private const string RUN_LOCATION = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run";
        private readonly string _appName = appName ?? throw new ArgumentNullException(nameof(appName), "应用程序名称不能为空");
        private readonly string _executablePath = appPath ?? Environment.ProcessPath
                ?? throw new InvalidOperationException("无法获取应用程序路径");
        private readonly string? _arguments = arguments;

        /// <summary>
        /// 初始化时验证参数
        /// </summary>
        static StartupService()
        {
            if (!OperatingSystem.IsWindows())
            {
                throw new PlatformNotSupportedException("此功能仅支持Windows操作系统");
            }
        }

        /// <summary>
        /// 验证构造函数参数
        /// </summary>
        [SupportedOSPlatform("windows")]
        private void ValidateParameters()
        {
            // 验证文件是否存在
            if (!File.Exists(_executablePath))
            {
                throw new FileNotFoundException($"指定的应用程序路径不存在: {_executablePath}", _executablePath);
            }

            // 验证文件是否为可执行文件
            if (!IsExecutableFile(_executablePath))
            {
                throw new ArgumentException($"指定的文件不是有效的可执行文件: {_executablePath}", nameof(appPath));
            }
        }

        /// <summary>
        /// 检查文件是否为可执行文件
        /// </summary>
        [SupportedOSPlatform("windows")]
        private static bool IsExecutableFile(string filePath)
        {
            try
            {
                // 检查文件扩展名
                if (!filePath.EndsWith(".exe", StringComparison.OrdinalIgnoreCase))
                {
                    return false;
                }

                // 尝试获取文件版本信息，进一步验证是否为有效的可执行文件
                var fileVersionInfo = FileVersionInfo.GetVersionInfo(filePath);
                return fileVersionInfo != null;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 获取完整的启动命令
        /// </summary>
        [SupportedOSPlatform("windows")]
        private string GetStartupCommand()
        {
            // 如果路径中包含空格，需要用引号括起来
            var quotedPath = _executablePath.Contains(' ') ? $"\"{_executablePath}\"" : _executablePath;

            return string.IsNullOrEmpty(_arguments)
                ? quotedPath
                : $"{quotedPath} {_arguments}";
        }

        /// <summary>
        /// 设置开机启动
        /// </summary>
        /// <exception cref="InvalidOperationException">无法访问注册表时抛出</exception>
        [SupportedOSPlatform("windows")]
        public void SetStartup()
        {
            ValidateParameters();

            using var key = Registry.CurrentUser.OpenSubKey(RUN_LOCATION, true)
                ?? throw new InvalidOperationException("无法访问注册表启动项");

            key.SetValue(_appName, GetStartupCommand());
        }

        /// <summary>
        /// 移除开机启动
        /// </summary>
        /// <exception cref="InvalidOperationException">无法访问注册表时抛出</exception>
        [SupportedOSPlatform("windows")]
        public void RemoveStartup()
        {
            using var key = Registry.CurrentUser.OpenSubKey(RUN_LOCATION, true)
                ?? throw new InvalidOperationException("无法访问注册表启动项");

            if (key.GetValue(_appName) != null)
            {
                key.DeleteValue(_appName, false);
            }
        }

        /// <summary>
        /// 检查是否已设置开机启动
        /// </summary>
        /// <returns>如果已设置开机启动则返回true，否则返回false</returns>
        /// <exception cref="InvalidOperationException">无法访问注册表时抛出</exception>
        [SupportedOSPlatform("windows")]
        public bool IsStartupSet()
        {
            using var key = Registry.CurrentUser.OpenSubKey(RUN_LOCATION)
                ?? throw new InvalidOperationException("无法访问注册表启动项");

            var value = key.GetValue(_appName)?.ToString();
            return value != null && value == GetStartupCommand();
        }
    }
}
